//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================



using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.DirectoryServices;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;

using LitwareHR.Portfolio.Contract;
using LitwareHR.Portfolio.Services.Properties;

using Shp.Runtime.Contract;
using Shp.Runtime.Services;
using SqlDataModel = LitwareHR.Portfolio.DataModel.Sql;
using SitkaDataModel = LitwareHR.Portfolio.DataModel.Sitka;

namespace LitwareHR.Portfolio.Services
{
    public static class ProvisioningLogic
    {
        private static readonly string[] rolesToCreate = new string[]
                                        {
                                            "Administrator",
                                            "EvaluateCandidate",
                                            "ApplyForAJob",
                                            "ManageUsersAndRoles",
                                            "ConfigureAndCustomize",
                                            "OpenPosition"
                                        };

        //TODO: just keep one of the datamodels. 
        private static SqlDataModel.ProvisioningDataModel dataModelSql = new SqlDataModel.ProvisioningDataModel();
        private static SitkaDataModel.ProvisioningDataModel dataModelSitka = new SitkaDataModel.ProvisioningDataModel();

        public static void DoProvisioning(string tenantName, string tenantAlias, int domainModel, string adminPassword)
        {
            try
            {
                tenantAlias = tenantAlias.ToLower();
                if (!TenantExists(tenantAlias))
                {
                    Guid tenantId = Guid.NewGuid();
                    ProvisioningCore(tenantId, tenantName, tenantAlias, adminPassword);
                }

                else
                {
                    throw new ProvisioningException(String.Format(Resources.TenantExistsException, tenantAlias), null);
                }
            }

            catch (Exception ex)
            {
                throw new ProvisioningException(ex.Message, ex);
            }
        }

        public static void DoProvisioning(string tenantName, string tenantAlias, int domainModel, string adminPassword, string silverlightAccountId, string silverlightAccountKey)
        {
            try
            {
                tenantAlias = tenantAlias.ToLower();
                if (!TenantExists(tenantAlias))
                {
                    Guid tenantId = Guid.NewGuid();
                    ProvisioningCore(tenantId, tenantName, tenantAlias, adminPassword);
                    
                    
                    dataModelSql.ProvisionSilverlightStreaming(tenantId, silverlightAccountId, silverlightAccountKey);
                    dataModelSitka.ProvisionSilverlightStreaming(tenantId, silverlightAccountId, silverlightAccountKey);
                }

                else
                {
                    throw new ProvisioningException(String.Format(Resources.TenantExistsException, tenantAlias), null);
                }
            }

            catch (Exception ex)
            {
                throw new ProvisioningException(ex.Message, ex);
            }
        }

        private static void ProvisioningCore(Guid tenantId, string tenantName, string tenantAlias, string adminPassword)
        {            
            PerformWebServerProvisioning(tenantAlias);
            
            dataModelSql.PerformModulesProvisioning(tenantId, tenantName, tenantAlias);
            dataModelSitka.PerformModulesProvisioning(tenantId, tenantName, tenantAlias, Guid.NewGuid(), Guid.NewGuid());            

            PerformAuthenticationProvisioning(tenantAlias, adminPassword);
        }

        private static void PerformAuthenticationProvisioning(string tenantAlias, string adminPassword)
        {
            AuthenticationLogic.SetUpTenant(tenantAlias);
            
            Upn newUser = new Upn("Admin", tenantAlias);
            AuthenticationLogic.CreateUser(newUser, adminPassword, string.Format(CultureInfo.InvariantCulture, "Admin@{0}", tenantAlias));

            foreach (string role in rolesToCreate)
            {
                AuthenticationLogic.CreateRole(tenantAlias, role);
                AuthenticationLogic.AddUserToRole(newUser, role);
            }
        }

        private static void PerformWebServerProvisioning(string tenantAlias)
        {
            string serviceHostDeploymentType = ConfigurationManager.AppSettings["ServiceHostDeploymentType"];
            if (serviceHostDeploymentType.Equals("local"))
            {
                string webServer = ConfigurationManager.AppSettings["WebServer"];
                string websiteIdentifier = ConfigurationManager.AppSettings["WebServerWebsiteIdentifier"];
                string publicAppPhysicalPath = ConfigurationManager.AppSettings["PublicAppPhysicalPath"];
                string privateAppPhysicalPath = ConfigurationManager.AppSettings["PrivateAppPhysicalPath"];
                string appServerTenantPhysicalPath = ConfigurationManager.AppSettings["AppServerTenantPhysicalPath"];
                WindowsIdentityImpersonate newIdentity = new WindowsIdentityImpersonate();                
                if (newIdentity.Impersonate(ConfigurationManager.AppSettings["ProvisioningUser"], Environment.MachineName, ConfigurationManager.AppSettings["ProvisioningPassword"]))
                {
                    try
                    {
                        IIS7VirtualDirectoryProvisioner.AddVirtualFolder(webServer, Int64.Parse(websiteIdentifier), tenantAlias, appServerTenantPhysicalPath);
                        IIS7VirtualDirectoryProvisioner.AddApplication(webServer, Int64.Parse(websiteIdentifier), String.Concat(tenantAlias, "/public"), publicAppPhysicalPath);
                        IIS7VirtualDirectoryProvisioner.AddApplication(webServer, Int64.Parse(websiteIdentifier), String.Concat(tenantAlias, "/private"), privateAppPhysicalPath);                        
                    }
                    finally
                    {
                        newIdentity.Undo();
                    }
                }
            }
            else if (serviceHostDeploymentType.Equals("distributed"))
            {
                throw new NotImplementedException();
            }
            else
            {
                throw new ConfigurationErrorsException("The appSettings key named ServiceHostDeployment has an invalid value");
            }
        }

        private static bool TenantExists(string tenantAlias)
        {
            try
            {
                if (SystemLogic.GetTenantId(tenantAlias) != Guid.Empty)
                {
                    return true;
                }

                return false;
            }
            catch
            {
                return false;
            }
        }


    }
}
